#pragma once
#include "Socket.hpp"
#include <jsoncpp/json/json.h>

using namespace SocketModule;

class Request
{
public:
    Request(){}

    Request(int x,int y,char oper):_x(x),_y(y),_oper(oper)
    {}

    std::string Serialize()//序列化：结构化数据转为字符串
    {
        Json::Value root;
        root["x"] = _x;
        root["y"] = _y;
        root["oper"] = _oper;

        Json::FastWriter writer;
        std::string s = writer.write(root);
        return s;
    }

    bool Deserialize(std::string& in)//反序列化
    {
        Json::Value root;
        Json::Reader reader;
        bool ok = reader.parse(in,root);
        if(ok)
        {
            _x = root["x"].asInt();
            _y = root["y"].asInt();
            _oper = root["oper"].asInt();
        }
        return ok;
    }

    int GetX(){return _x;}
    int GetY(){return _y;}
    char GetOper(){return _oper;}

    ~Request(){}

private:
    int _x;//第一个操作数
    int _y;//第二个操作数
    char _oper;//操作符号
};

class Response
{
public:
    Response(){}

    Response(int result,int code):_result(result),_code(code)
    {}

    std::string Serialize()
    {
        Json::Value root;
        root["result"] = _result;
        root["code"] = _code;

        Json::FastWriter writer;
        std::string s = writer.write(root);
        return s;
    }

    bool Deserialize(std::string& in)
    {
        Json::Value root;
        Json::Reader reader;
        bool ok = reader.parse(in,root);
        if(ok)
        {
            _result = root["result"].asInt();
            _code = root["code"].asInt();
        }
        return ok;
    }

    void SetResult(int result){_result = result;}
    void SetCode(int code){_code = code;}

    void ShowResult()
    {
        std::cout<<"Result:"<<_result<<" Code:"<<_code<<std::endl;
    }

    ~Response(){}

private:
    int _result;//计算结果
    int _code;//0表示结果正常，1表示除0异常
};

//协议必须解决的两个问题
//1.request和responce都必须有序列化和反序列化的功能（上述已经实现）
//2.必须保证读取的报文是完整的一个请求（TCP考虑，UDP不用考虑）
//至于怎么处理完整报文，不交给该协议层处理，使用业务层的回调函数即可
//将结构化数据的请求Request交给业务层然后返回结构化数据的结果Responce即可
using func_t = std::function<Response(Request&)>;
const std::string sep = "\r\n";

class Protocol
{
public:
    Protocol(){}
    Protocol(func_t func):_func(func)
    {}

    std::string Encode(const std::string& jsonstr)//添加报头
    {
        std::string len = std::to_string(jsonstr.size());
        return len + sep + jsonstr + sep;
        //50\r\n{...}\r\n
    }

    // 以下情况都可能出现：
    // 50\r\n{"x": 10, "y" : 20, "oper" : '+'}\r\n
    // 5
    // 50
    // 50\r
    // 50\r\n
    // 50\r\n{"x": 10, "
    // 50\r\n{"x": 10, "y" : 20, "oper" : '+'}\r\n
    // 50\r\n{"x": 10, "y" : 20, "oper" : '+'}\r\n50\r\n{"x": 10, "y" : 20, "ope

    bool Decode(std::string& buffer,std::string* package)//提取一个完整的报文到package中,并删除（因此是引用）
    {
        ssize_t pos = buffer.find(sep);//先找到分隔符
        if(pos == std::string::npos)
            return false;//继续读数据，直到有一个分隔符
        std::string package_len_str = buffer.substr(0,pos);//拿到“50”
        int package_len_int = std::stoi(package_len_str);//拿到50
        //得到完整报文的目标长度，若没达到就继续读
        int target_len = package_len_str.size() + package_len_int + 2*sep.size();
        if(buffer.size() < target_len)
            return false;
        
        //到这里就必定有完整的一个报文了
        *package = buffer.substr(pos+sep.size(),package_len_int);
        buffer.erase(0,target_len);
        return true;
    }

    //获取请求
    void GetRequest(std::shared_ptr<Socket>& sock,InetAddr& client)
    {
        std::string buffer_queue;
        while(true)
        {
            int n = sock->Recv(&buffer_queue);
            if(n > 0)
            {
                std::cout << "buffer_queue:" << buffer_queue << std::endl;
                //1.检测是否取得了一个完整的报文
                std::string json_package;
                bool ret = Decode(buffer_queue,&json_package);
                if(!ret)
                    continue;

                std::cout<<"获取到的请求："<<json_package<<std::endl;
                
                //2.到这里一定取得了一个完整的报文,进行反序列化
                Request req;
                bool ok = req.Deserialize(json_package);
                if(!ok)
                    continue;
                
                //3.到这里Request里的属性x,y,oper就已经被设置了,处理交给业务层
                Response res = _func(req);

                //4.将结果序列化后发送
                std::string json_str = res.Serialize();
                std::string send_json_str = Encode(json_str);
                sock->Send(send_json_str);
            }
            else if(n == 0)
            {
                LOG(LogLevel::INFO) << "client:"<<client.StringAddr() << " Quit";
                break;
            }
            else
            {
                LOG(LogLevel::WARNING) << "client:"<<client.StringAddr() << " Recv error";
                break;
            }
        }
    }
    
    //获取应答
    bool GetResponse(std::shared_ptr<Socket>& client,std::string& res_buffer,Response* res)
    {
        while(true)
        {
            int n = client->Recv(&res_buffer);
            if(n > 0)
            {
                std::string json_package;
                while(Decode(res_buffer,&json_package))
                {
                    //到这里一定已经拿到了一个完整应答报文
                    res->Deserialize(json_package);
                }
                return true;
            }
            else if(n == 0)
            {
                LOG(LogLevel::INFO) << "Server Quit";
                return false;
            }
            else
            {
                LOG(LogLevel::WARNING) << "Recv error";
                return false;
            }
        }
    }

    //构造请求，序列化后返回发送的字符串
    std::string BuildRequestString(int x,int y,char oper)
    {
        Request req(x,y,oper);
        std::string json_req = req.Serialize();
        return Encode(json_req);
    }

    ~Protocol(){}
private:
    func_t _func;//读取到完整报文后交给业务层处理，该协议层不关心
};